package ModbusTCP

import (
	"encoding/json"
	"log"

	"net"
	"time"
)

type protocol struct {
	IP       string `json:"IP"`
	ID       int    `json:"ID"`
	Register string `json:"Register"`
	Addr     int    `json:"Addr"`
	Swap     bool   `json:"Swap"`
	Bit      int    `json:"Bit"`
}
type writedata struct {
	id    int
	value interface{}
}
type tag struct {
	TagID int
	Type  string
	Swap  bool
	Bit   int
	Read  []byte
	Write []byte
	Value interface{}
}

var tagslist map[string][]tag
var chanlist map[string]chan writedata
var callback func(ID int, Data interface{}, Time int64)

func AddTag(ID int, Type string, Protocol string) (err error) {
	var p protocol
	var t tag
	err = json.Unmarshal([]byte(Protocol), &p)
	if err != nil {
		return err
	}
	t.TagID = ID
	t.Type = Type
	t.Swap = p.Swap
	t.Bit = p.Bit
	t.Read = p.getRead(Type)
	t.Write = p.getWrite(Type)
	v, ok := tagslist[p.IP]
	if !ok {
		tagslist[p.IP] = []tag{t}
		chanlist[p.IP] = make(chan writedata)
	} else {
		v = append(v, t)
		tagslist[p.IP] = v
	}
	return
}
func Write(ID int, Value interface{}) {
	for i, v := range tagslist {
		for _, v2 := range v {
			if v2.TagID == ID {
				chanlist[i] <- writedata{
					id:    ID,
					value: Value,
				}
				goto End
			}
		}
	}
End:
}
func Start(f func(ID int, Data interface{}, Time int64)) {
	callback = f
	for i, v := range tagslist {
		go link(i, v, chanlist[i])
	}
}
func link(ip string, tags []tag, w chan writedata) {
	C := time.Tick(1000 * time.Millisecond)
	for {
		conn, err := net.Dial("tcp", ip)
		if err == nil {
			log.Print("Conn success")
			defer func() {
				_ = conn.Close()
				conn = nil
			}()
			run(conn, tags, w)
		}
		<-C
	}
}

func run(conn net.Conn, tags []tag, w chan writedata) {
	var err error
	C := time.Tick(1000 * time.Millisecond)
	for {
		select {
		case t := <-w:
			for i, v := range tags {
				if v.TagID == t.id {
					err := tags[i].write(conn, t.value)
					if err != nil {
						goto End
					}
					break
				}
			}
		case <-C:
			for i := range tags {
				err = tags[i].read(conn)
				if err != nil {
					goto End
				}
			}
		}
	}
End:
}
func init() {
	tagslist = make(map[string][]tag)
	chanlist = make(map[string]chan writedata)
}
